package net.borderwars.robots;

import net.borderwars.map.Map;
import net.borderwars.map.Mappable;
import net.borderwars.map.Movable;

import java.util.Random;

/**
 * @author Eric
 *         Date: Mar 5, 2005
 *         Time: 2:45:04 PM
 */
public abstract class AbstractMovable implements Movable {
    static Random r = new Random();
    protected int x = r.nextInt(999);
    protected int y = r.nextInt(999);
    static private int gid = 0;
    protected int id = gid++;
    protected VirtualMachine vm = null;
    protected Map map = null;
    static int[][] distanceTable = null;

    public void setup(VirtualMachine vm, Map m) {
        this.vm = vm;
        this.map = m;
    }

    public static int calcDistance(Mappable one, Mappable two) {
        return (calcDistance(one.loc_x(), one.loc_y(), two.loc_x(), two.loc_y()));
    }

    public static int calcDistance(int x1, int y1, int x2, int y2) {
        int dx = Math.abs(x2 - x1);
        int dy = Math.abs(y2 - y1);
        if (distanceTable == null) {
            distanceTable = new int[1000][1000];
            for (int y = 0; y < 1000; y++) {
                for (int x = 0; x < 1000; x++) {
                    int d = (int) Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
                    distanceTable[x][y] = d;
                }
            }

        }
        return (distanceTable[dx][dy]);
    }

    protected int angleTo(Mappable m) {
        return (angleTo(m.loc_x(), m.loc_y()));
    }

    public static double calcAngle(float x1, float y1, float x2, float y2) {
        float dx = x2 - x1;
        float dy = y2 - y1;
        double angle = 0.0d;

        // Calculate angle
        if (dx == 0.0) {
            if (dy == 0.0) {
                angle = 0.0;
            } else if (dy > 0.0) {
                angle = Math.PI / 2.0;
            } else {
                angle = Math.PI * 3.0 / 2.0;
            }
        } else if (dy == 0.0) {
            if (dx > 0.0) {
                angle = 0.0;
            } else {
                angle = Math.PI;
            }
        } else {
            if (dx < 0.0) {
                angle = Math.atan(dy / dx) + Math.PI;
            } else if (dy < 0.0) {
                angle = Math.atan(dy / dx) + (2 * Math.PI);
            } else {
                angle = Math.atan(dy / dx);
            }
        }

        // Convert to degrees
        angle = angle * 180 / Math.PI;

        // Return
        return angle;
    }

    /**
     * Gets the angle between this robot and those coordinates
     * in DEGREES
     *
     * @param x
     * @param y
     * @return vggf
     */
    protected int angleTo(int x, int y) {
        int angle = (int) calcAngle(loc_x(), loc_y(), x, y);
        return (angle);
//        double tan = Math.atan2(loc_y()-y, loc_y()-x);
//        return ( (int)Math.toDegrees(tan));

//
//        int curx, nx, ny, dir;
//        nx = (curx = loc_x()) - x;
//        ny = (loc_y() - y) * 100000;
//
//        if (nx == 0) {  // why do we do this? cuz we are too lazy to really deal with DBZ
//            nx = 1;
//        }
//
//        if (x > curx)
//            dir = 360 + atan(ny / nx);
//        else
//            dir = 180 + atan(ny / nx);
//
//        dir %=360;
//        return (dir);

    }

    public int rand(int limit) {
        double rv = r.nextDouble();
        rv = rv * limit;
        return ((int) rv);
    }

    public int sqrt(int number) {
        return (int) Math.sqrt(number);
    }

    public int sin(int degree) {
        double radians = Math.toRadians(degree);
        double answer = Math.sin(radians);
        answer *= 100000;
        return (int) answer;
    }

    public int cos(int degree) {
        double radians = Math.toRadians(degree);
        double answer = Math.cos(radians);
        answer *= 100000;
        return (int) answer;
    }

    public int tan(int degree) {
        double radians = Math.toRadians(degree);
        double answer = Math.tan(radians);
        answer *= 100000;
        return (int) answer;
    }

    public int atan(int ratio) {
        return (int) Math.toDegrees(Math.atan(ratio));
    }

    public int getId() {
        return (id);
    }

    public VirtualMachine getVM() {
        return (vm);
    }
}
